import { BuildConfig, BuildInfo, ReplaceContent } from "./src/classes.mjs";
import { Asyncer, BuildBundle, BuildFrame, BuildGame, DirForeach, FindProjectRoot, GetArgInd, GetArgValueByInd, GetBuildTarget, GetBundleList, GetMD5Path, HasArg, ReadBuildConfig } from "./src/utils.mjs";
import process from 'process'
import { execSync } from 'child_process'
import fs from 'fs'
import path from 'path'
import jszip from 'jszip'
import { dirname } from 'path';
const __dirname = dirname(process.argv[1]);

//打包内容
// 版本 test / res
// 改文件
// 压缩
// zip

let hasAction = false;
let argvs = process.argv.slice(2);

if (argvs.length == 0 || HasArg("-h")) {
    console.log(fs.readFileSync(path.resolve(__dirname, "readme.md")).toString());
    process.exit(0);
}
const ROOT_PATH = FindProjectRoot();
if (!ROOT_PATH) {
    console.error(`没有找到cocos项目文件夹`);
    process.exit(1);
}
console.log(`cocos项目文件夹:${ROOT_PATH}`);

const buildPath = path.resolve(ROOT_PATH, "build/web-mobile");

const info = new BuildInfo();
if (fs.existsSync(path.resolve(buildPath, "build.info"))) {
    Object.assign(info, JSON.parse(fs.readFileSync(path.resolve(buildPath, `build.info`)).toString()));
}
let curTarget = "";
if (HasArg("-v")) {
    curTarget = GetArgValueByInd(GetArgInd("-v") + 1);
    if (!curTarget) {
        curTarget = "test";
    }
    else if (curTarget != "test" && curTarget != "res") {
        curTarget = "test";
    }
}

if (info.target && curTarget && info.target != curTarget) {
    console.warn(`旧构建目标为${info.target}，-v ${curTarget}参数无效`);
}
else if (!info.target && !curTarget) {
}
else if (!info.target && curTarget) {
    info.target = curTarget;
}

if (!info.target) {
    info.target = "test";
    console.warn("无指定构建目标，自动使用test");
}
else {
    console.log(`构建目标(${info.target})`);
}

if (!info.build) {
    if (fs.existsSync(buildPath)) {
        console.log(`build/web-mobile/ 存在，写入 build/web-mobile/build.info `);
        info.build = true;
        fs.writeFileSync(`${buildPath}/build.info`, JSON.stringify(info));
    }
    else {
        console.log(`${buildPath}为空，开始使用cocos构建web-mobile，并写入${buildPath}/build.info`);
        if (!process.env.CREATOR_URL_24X) {
            console.warn("请设置系统变量 CREATOR_URL_24X ，指向 2.4.x版本的cocoscreator.exe 并重启编辑器。");
            process.exit(0);
        }

        let st = `${process.env.CREATOR_URL_24X} --path ${ROOT_PATH} --build `;
        if (GetBuildTarget() == "res") {
            st += "platform=web-mobile;debug=false;sourceMaps=false"
        }
        else {
            st += "platform=web-mobile;debug=true;sourceMaps=true"
        }
        console.log(st)
        await execSync(st);
        info.build = true;
        fs.writeFileSync(`${buildPath}/build.info`, JSON.stringify(info));
        hasAction = true;
        console.log(`web-mobile构建完成`);
    }
}

await new Promise(ok => setTimeout(ok, 100));
if (HasArg("-m") || HasArg("--all")) {
    if (!info.mod) {
        //读取配置
        /**
         * @type { BuildConfig }
         */
        const config = ReadBuildConfig(info.target);
        if (!config) {
            console.error(`没有找到${ROOT_PATH}/build_config_${info.target}.json`);
            process.exit(1);
        }

        {
            //修改index.html
            const loadingDomPath = await GetMD5Path(buildPath, "loading_dom", "js");
            const indexPath = await GetMD5Path(buildPath, "index", "html");

            let str = fs.readFileSync(indexPath).toString();
            str = str
                .replace(/<title>(.*)<\/title>/i, `<title>${config.title}</title>`)
                .replace(/<script\s+src="main\.(\d+)\.js"\s+charset="utf-8"><\/script>/gi, function (match, version) {
                    return `${match}<script src="${loadingDomPath.substring(loadingDomPath.lastIndexOf("/") + 1)}"></script>`;
                })
                //修改COCOS脚本
                .replace("(function () {", `var LoadCocos = function(){`)
                .replace("})();", `};LoadCocos();`);
            let rc = new ReplaceContent(`*\n</head>`, config.assemblerHeadContent());
            str = rc.replace(str);
            for (let key in config.index_replace_content) {
                let rc = new ReplaceContent(key, config.index_replace_content[key]);
                str = rc.replace(str);
            }
            fs.writeFileSync(indexPath, str);
        }

        {
            //修改 main/index.js
            const mainIndexPath = await GetMD5Path(path.resolve(buildPath, "assets/main/"), "index", "js");
            let str = fs.readFileSync(mainIndexPath).toString();

            str = str
                .replace(/BUILD_TARGET\s*:\s*"(.*?)"/g, `BUILD_TARGET:"${info.target}"`)
                ;
            fs.writeFileSync(mainIndexPath, str);
        }
        hasAction = true;
        info.mod = true;
        fs.writeFileSync(path.resolve(buildPath, "build.info"), JSON.stringify(info));
        console.log("--- 修改文件完成");
    }
}

if (HasArg("-c") || HasArg("--all")) {
    if (!info.compress) {
        hasAction = true;
        info.compress = true;
        fs.writeFileSync(path.resolve(buildPath, "build.info"), JSON.stringify(info));
        let pms = [];
        let total = 0;
        let cur = 0;
        let str = `pngquant压缩图片:(${cur}/${total})`;
        process.stdout.write(str);
        await DirForeach(buildPath, true,
            async (dirent, path) => { //dir
            },
            async (dirent, path) => { //file
                let ext = path.substring(path.lastIndexOf(".") + 1, path.length);
                if (ext == "png") {
                    total++;
                    str = `pngquant压缩图片:(${cur}/${total}) ${path}`;
                    process.stdout.write(str + "\r");

                    let pm = new Promise(async ok => {
                        await execSync(`pngquant -f --ext .png --quality 10-90 --speed 1 "${path}"`);
                        ok();
                    })
                    // console.log(`pngquant: 压缩图片"${path}"`);
                    pm.then(() => {
                        cur++;
                        str = `pngquant压缩图片:(${cur}/${total}) ${path}`;
                        process.stdout.write(str + "\r");
                    });
                    // let pm = new Promise(async ok=>{
                    //     ok();
                    // });
                    // pm.then(() => {
                    // });
                    pms.push(pm);
                }
            }
        );
        await Promise.all(pms);
        process.stdout.write("\r\n");
        console.log("--- 压缩PNG完成");
    }
}
if (HasArg("--all")) {
    hasAction = true;
    await BuildFrame(false);
    await BuildGame(path.resolve(ROOT_PATH, `build/frame-${info.target}/games`), "", info, false);
    let bundleList = await GetBundleList();
    await BuildBundle(path.resolve(ROOT_PATH, `build/frame-${info.target}/bundles`),
        bundleList,
        info,
        false
    );
}
if (HasArg("-z") || HasArg("--all")) {
    let fileName = path.resolve(ROOT_PATH, `build/${info.target}-${(new Date()).format("yy-MM-dd_hh_mm_ss")}.zip`);
    const zip = new jszip();
    let zf = zip.folder(buildPath);
    let stack = [zf];
    await DirForeach(buildPath, true,
        async (dirent, path) => { //dir
            stack.unshift(zf.folder(dirent.name));
        },
        async (dirent, path) => { //file
            stack[0].file(dirent.name, fs.readFileSync(path));
        },
        (dirent, path) => { //close dir
            stack.shift();
        },
    );

    let content = await zip.generateAsync({ type: "nodebuffer", compression: "DEFLATE" });
    fs.writeFileSync(fileName, content);
    hasAction = true;
    console.log("--- ZIP打包完成");
}

else if (HasArg("--frame-game")) {
    hasAction = true;
    await BuildFrame(false);
    await BuildGame(path.resolve(ROOT_PATH, `build/frame-${info.target}/games`), "", info, false);
}
else if (HasArg("--frame-bundles")) {
    hasAction = true;
    await BuildFrame(false);
    let bundleList = await GetBundleList();
    await BuildBundle(path.resolve(ROOT_PATH, `build/frame-${info.target}/bundles`),
        bundleList,
        info,
        false
    );
}
else if (HasArg("--frame")) {
    hasAction = true;
    await BuildFrame(false);
}

await Asyncer.awaitAllJobDone();
if (!hasAction) {
    console.warn("--- 执行完毕，没有有效变化");
}
process.exit(0);